/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url: string): { [key: string]: any } {
  // eslint-disable-next-line
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf('?') + 1);
  const obj: { [key: string]: any } = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * 获取string的字节数
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str: string): number {
  // returns the byte length of an utf8 string
  let s = str.length;
  for (let i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual: any[]): any[] {
  const newArray = [];
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {string}
 */
export function object2url(json: { [key: string]: any }): string {
  if (!json) return '';
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) return '';
      return `${encodeURIComponent(key)}=${encodeURIComponent(json[key])}`;
    }),
  ).join('&');
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function url2Object(url: string): { [key: string]: any } {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ');
  if (!search) {
    return {};
  }
  const obj: { [key: string]: any } = {};
  const searchArr = search.split('&');
  searchArr.forEach(v => {
    const index = v.indexOf('=');
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val: string): string {
  const div = document.createElement('div');
  div.innerHTML = val;
  return div.textContent || div.innerText;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(
  target: { [key: string]: any },
  source: any,
): { [key: string]: any } {
  if (typeof target !== 'object') {
    // eslint-disable-next-line
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === 'object') {
      // eslint-disable-next-line
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      // eslint-disable-next-line
      target[property] = sourceProperty;
    }
  });
  return target;
}

/**
 * lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source: {
  [key: string]: any;
}): { [key: string]: any } {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments of deepClone');
  }
  const targetObj: any = source.constructor === Array ? [] : {};
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}

/**
 * 数组 ES6 去重
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr<T>(arr: Array<T>): Array<T> {
  return Array.from(new Set(arr));
}

/**
 * 返回唯一字符串
 * @returns {string} eg: "142a157mh1c80"
 */
export function createUniqueString(): string {
  const timestamp = `${+new Date()}`;
  const randomNum = (1 + Math.random()) * 65536;
  const sRandomNum = `${Math.floor(randomNum)}`;
  return (+(sRandomNum + timestamp)).toString(32);
}
